package org.xteam.sled.decoder;

import java.util.ArrayList;
import java.util.List;

import org.xteam.parser.runtime.AstList;
import org.xteam.parser.runtime.Span;
import org.xteam.parser.runtime.reflect.AstNodeType;
import org.xteam.sled.ast.CallPattern;
import org.xteam.sled.ast.Equation;
import org.xteam.sled.ast.Expr;
import org.xteam.sled.ast.IdentExpr;
import org.xteam.sled.ast.IdentOpName;
import org.xteam.sled.ast.OpName;
import org.xteam.sled.matcher.Arm;
import org.xteam.sled.matcher.ArmBuilder;
import org.xteam.sled.model.LatentPattern;
import org.xteam.sled.semantic.ConstructorType;
import org.xteam.sled.semantic.InstructionConstructor;
import org.xteam.sled.semantic.Operand;
import org.xteam.sled.semantic.OperandSyntax;
import org.xteam.sled.semantic.SemanticContext;

public class DecoderBuilder {

	public static class recognized_constructor {

		private InstructionConstructor cons;
		private List<String> operands;

		public recognized_constructor(InstructionConstructor cons,
				List<String> operands) {
			this.cons = cons;
			this.operands = operands;
		}
	};

	public static class recognizer {

		private ConstructorType constype;
		private Match<recognized_constructor> matcher;
		
		public recognizer(ConstructorType constype,
				Match<recognized_constructor> matcher) {
			this.constype = constype;
			this.matcher = matcher;
		}

		public Match<recognized_constructor> getMatch() {
			return matcher;
		}
	}

	public static class Match<T> {

		private List<Arm> arms;

		public Match(List<Arm> arms) {
			this.arms = arms;
		}
		
		public List<Arm> getArms() {
			return arms;
		}

	}
	
	public List<recognizer> decoder(SemanticContext spec) {
		List<recognizer> res = new ArrayList<recognizer>();
		for (ConstructorType ct : spec.getConstructorTypes()) {
			res.add(recognizer(spec, ct));
		}
		return res;
	}

	public recognizer recognizer(SemanticContext spec, ConstructorType constype) {
		List<Arm> arms = new ArrayList<Arm>();
		for (InstructionConstructor member : constype.getMembers()) {
			arms.addAll(arm(spec, member));
		}
		return answer(constype, arms);
	}

	private List<Arm> arm(SemanticContext spec, InstructionConstructor cons) {
		String name = cons.name();
		List<Operand> operands = cons.getOperands();
		List<LatentPattern> branches = cons.getBranches();
		List<OperandSyntax> syntax = cons.getOperandSyntax();
		List<String> opnames = new ArrayList<String>();
		for (Operand op : operands) {
			opnames.add(op.name());
		}
		recognized_constructor code = new recognized_constructor(cons, opnames);
		AstList<Expr> args = new AstList<Expr>((AstNodeType) null);
		for (String opname : opnames) {
			args.add(new IdentExpr(new Span(-1, -1), opname));
		}
		CallPattern pat = new CallPattern(null, new AstList<OpName>(null,
				new IdentOpName(new Span(-1, -1), name)), args);
		return new ArmBuilder(pat, new ArrayList<Equation>(), null, code)
				.elaborate(spec, 0 /*cons.tag()*/, "successor");
	}

	private recognizer answer(ConstructorType constype, List<Arm> arms) {
		return new recognizer(constype, new Match<recognized_constructor>(
				// value = fn ty => C.Patterns.Exp.var "PC"
				// succptr = SOME "successor"
				arms /* rev */ // reverse to put synthetics first
		));
	}

	/*
	 * public Object tosx (Object x) { // x = {cons, operands} let val name =
	 * #name (Constructor.info cons) in SxUtil.list [Sx.ATOM "constructor",
	 * SxUtil.list (map Sx.ATOM (name :: operands))] end }
	 */

}
